<?php

class PlantService extends AbstractService
{

    /**
     * @var PlantService
     */
    private static $instance;

    /**
     * Get instance of PlantService.
     *
     * @return PlantService
     */
    public static function get()
    {
        if (!self::$instance) {
            self::$instance = new PlantService();
        }

        return self::$instance;
    }

    /**
     * Construction.
     */
    protected function __construct()
    {
        parent::__construct();
    }

    /**
     * 处理创建时的逻辑
     *
     * @param int $userId
     * @param GroundVoList $groundList
     * @return void
     */
    public function handleCreate($userId, $groundList = null)
    {
        $reqTime = GameService::get()->getReqTime();
        $plantSettings = SzConfig::get()->loadAppConfig(GameConst::CONFIG_GROUND_PLANT, null, true);

        foreach ($plantSettings as $plantSetting) {
            $gridId = $plantSetting['anchorX'] . 'x' . $plantSetting['anchorY'];
            $this->plant($userId, $gridId, $plantSetting['itemDefId'], $reqTime - $plantSetting['reduceTime'], $groundList,false);
        }
    }

    /**
     * 处理登录时的逻辑
     *
     * @param int $userId
     * @return void
     */
    public function handleLogin($userId)
    {
        $this->updateWithCacheMerge($userId);
    }

    /**
     * 提供当前 service 数据
     *
     * @param int $userId
     * @return array(PlantVoList)
     */
    public function info($userId)
    {
        $plantList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_PLANT);

        foreach ($plantList->getList() as $decorId => $plant) {
            $plant = $this->getWithCacheMerge($userId, $plant);
            $plantList->updateElement($decorId, $plant);
        }
        return array(
            $plantList
        );
    }

    /**
     * 获取偷花信息
     *
     * @param int $userId
     * @param PlantVo $plant
     * @param array $friendCaches
     * @return PlantVo
     */
    public function getWithCacheMerge($userId, $plant, $friendCaches = null)
    {
        $decorId = $plant->getDecorId();
        $seedId = $plant->getSeedId();
        if ($seedId == -1) {
            return $plant;
        }
        if (is_null($friendCaches)) {
            $friendCaches = SzCacheFactory::get()->getAppCache($userId)->hGetAll(GameConst::CACHE_KEY_PLANT_STEAL_INFO . $decorId . '_' . $userId);
            if (!$friendCaches) {
                return $plant;
            }
        }

        $stealInfo = $plant->getRawStealInfo();
        $harvestCount = $plant->getHarvestCount();

        foreach ($friendCaches as $targetId => $count) {
            $stealInfo[$targetId] = $count;
            $harvestCount -= $count;
        }

        $cropSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_PLANT_CROP, $seedId, true);
        if ($harvestCount < $cropSetting['baodi'][$plant->getLevel()]) {
            $harvestCount = $cropSetting['baodi'][$plant->getLevel()];
        }
        $plant->setStealInfo($stealInfo);
        $plant->setHarvestCount($harvestCount);
        return $plant;
    }

    /**
     * 用户登录后，刷新偷花信息
     *
     * @param int $userId
     * @return void
     */
    public function updateWithCacheMerge($userId)
    {
        $plantList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_PLANT);

        /** @var PlantVo $plant */
        foreach ($plantList->getList() as $decorId => $plant) {

            // 读取 Redis 中偷花的缓存数据
            $friendCaches = SzCacheFactory::get()->getAppCache($userId)->hGetAll(GameConst::CACHE_KEY_PLANT_STEAL_INFO . $decorId . '_' . $userId);
            if (!is_array($friendCaches) || count($friendCaches) == 0) {
                continue;
            }

            // 重新计算玩家偷花的数据
            $plant = $this->getWithCacheMerge($userId, $plant, $friendCaches);
            $plantList->updateElement($decorId, $plant);
            // 清除 Redis 中的好友帮助缓存数据
            SzCacheFactory::get()->getAppCache($userId)->delete(GameConst::CACHE_KEY_PLANT_STEAL_INFO . $decorId . '_' . $userId);
        }
        SzPersister::get()->setVoList($plantList);
    }

    /**
     * 摆放土地
     *
     * @param int $userId
     * @param int $itemDefId
     * @param array $gridIds
     * <pre>
     *  array(左下gridId， 右上gridId)
     * </pre>
     * @param array $blockIds
     * @param int $orient
     * @param int $reqTime
     * @throws SzException 20251, 20252
     * @return array(GroundVo, DecorVo)
     */
    public function putSoil($userId, $itemDefId, $gridIds, $blockIds, $orient, $reqTime)
    {
        $level = UserService::get()->getUserLevel($userId);
        $limitSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_PLANT_FIELD_COUNT, $level, true);
        $itemSetting = SzConfig::get()->loadAppConfig(ModuleItemConst::CONFIG_ITEM_DEFS, $itemDefId, true);

        // 验证土地上限配置是否存在
        $soilLimitKey = 'count_' . $itemSetting['type'];
        if (!SzUtility::checkArrayKey($soilLimitKey, $limitSetting)) {
            throw new SzException(20251, array($soilLimitKey, $level, GameConst::CONFIG_PLANT_FIELD_COUNT));
        }

        // 验证土地是否超过上限
        $soilCount = BuildingService::get()->getBuildingCount($userId, $itemDefId);
        $soilLimit = $limitSetting[$soilLimitKey];
        if ($soilCount >= $soilLimit) {
            throw new SzException(20252, array($itemDefId, $soilCount, $soilLimit));
        }

        return BuildingService::get()->put($userId, $itemDefId, $gridIds, $blockIds, $orient, $reqTime);
    }

    /**
     * 种植植株
     *
     * @param int $userId
     * @param int $gridId
     * @param int $seedId
     * @param int $reqTime
     * @param int $groundList = null
     * @throws SzException 20253,20254
     * @return PlantVo
     */
    public function plant($userId, $gridId, $seedId, $reqTime, $groundList = null,$needWater = true)
    {
        /**
         * @var BuildingVo $building
         */
        list($decorId, $building) = BuildingService::get()->getGroundAndDecorRecord($userId, $gridId, GameConst::GROUND_LAYER_TYPE_PLANT_LAYER_ID, $groundList);
        $buildingDefId = $building->getBuildingDefId();

        $cropSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_PLANT_CROP, $seedId, true);
        $itemSetting = SzConfig::get()->loadAppConfig(ModuleItemConst::CONFIG_ITEM_DEFS, $buildingDefId, true);
        $cropParameterSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_PLANT_CROP_PARAMETER, $buildingDefId, true);

        // 验证等级
        $userLv = UserService::get()->getUserLevel($userId);
        if ($userLv < $itemSetting['unlockLv']) {
            throw new SzException(20256, $userLv);
        }
        // 验证土地类型
        if ($cropSetting['type'] != $cropParameterSetting['type']) {
            throw new SzException(20253, array($seedId, $buildingDefId));
        }

        $seedList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_PLANT_SEED);
        $seedVo = $seedList->getElement($seedId, false);
        if (!$seedVo) {//种子未解锁
            throw new SzException(20260, array($seedId));
        }
        /**
         * @var PlantSeedVo $seedVo
         */
        $harvestCount = intval($cropSetting['cropCount'][$seedVo->getLevel()] * $cropParameterSetting['cropCount']);

        // 验证土地是否已经被种植
        /**
         * @var PlantVoList $plantList
         * @var PlantVo $plant
         */
        $plantList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_PLANT);
        $plant = $plantList->getElement($decorId, false);
        if (!$plant) {
            // 创建植株
            $plant = new PlantVo($decorId, $userId, -1, 0, 0, $harvestCount, GameConst::DEFAULT_JSON_STRING, 0,true);
        } else {
            $plant->setHarvestCount($harvestCount);
            $plant->setStealInfo([]);
        }
        if ($plant->getSeedId() != -1) {
            throw new SzException(20254, array($gridId, $plant->getSeedId()));
        }

        // 更新种子
        $plant->setSeedId($seedId);
        if (!$needWater) {
            $plant->setStatus(1);
        }

        /**
         * @var PlantSeedVo $seedVo
         */
        $plant->setLevel($seedVo->getLevel());
        if ($plant->isInsert() && !SzUtility::checkArrayKey($decorId, $plantList->getList())) {
            $plantList->setElement($decorId, $plant);
            $plantList->addElement($plant);
        } else {
            $plantList->updateElement($decorId, $plant);
        }

        SzPersister::get()->setVoList($plantList);

        //更新任务进度
        MissionService::get()->progress($userId, GameConst::ENTITY_ACTION_PLANT_PUT, GameConst::ENTITY_TYPE_ITEM, $seedId, 1);
        TreeService::get()->updateProgress($userId,GameConst::TREE_TASK_PLANT_FLOWER,1);
        NewTaskService::get()->updateDailyTask($userId,GameConst::DAILY_TASK_PLANT,1);
        TrainingService::get()->updateProgress($userId,GameConst::TRAINING_TASK_PLANT_FLOWER,1);

        return $plant;
    }

    /**
     * 种植植株
     * @param $userId
     * @param $gridId
     * @param $reqTime
     * @param $plantList
     * @param $cropSettings
     * @param $activityData
     * @return mixed
     * @throws SzException
     */
    public function water($userId, $gridId, $reqTime,$plantList,$cropSettings,$activityData)
    {
        /**
         * @var BuildingVo $building
         */
        list($decorId) = BuildingService::get()->getGroundAndDecorRecord($userId, $gridId, GameConst::GROUND_LAYER_TYPE_PLANT_LAYER_ID);
        $plant = $plantList->getElement($decorId);

        if ($plant->getSeedId() == -1) {
            throw new SzException(20261, array($decorId));
        }

        if ($plant->getStatus() != 0) {
            throw new SzException(20262, array($decorId));
        }

        // 更新状态与时间
        $plant->setStatus(1);
        $plant->setHarvestTime($reqTime);
        $plantList->updateElement($decorId, $plant);
        SzPersister::get()->setVoList($plantList);

        $tid = '';
        foreach ($cropSettings[$plant->getSeedId()]['consumption'] as $entityId => $count) {
            GameService::get()->handleEntity($userId, $entityId, $count, true);
            $tid .= "{$entityId}:{$count}|";
        }
        CommonFunctionService::get()->reportResourceUseDetails(GameConst::FUNC_PLANT_PLANT,$userId,0,$tid,'water');//消耗资源上报

        // 更新活动任务进度
        if (!empty($activityData)){
            ActivityTaskService::get()->updateActivityTaskProgress($userId,$activityData['aid'],$activityData['position']);
        }

        return $plant->toArray();
    }

    /**
     * 收获植株
     * @param $userId
     * @param $gridId
     * @param $reqTime
     * @param $plantList
     * @param $hasBuffFlower
     * @param $hasBuffSeed
     * @return array
     * @throws SzException
     */
    public function harvest($userId, $gridId, $reqTime,$plantList,$hasBuffFlower,$hasBuffSeed)
    {
        /**
         * @var BuildingVo $building
         */
        list($decorId, $building) = BuildingService::get()->getGroundAndDecorRecord($userId, $gridId, GameConst::GROUND_LAYER_TYPE_PLANT_LAYER_ID);

        $plant = $plantList->getElement($decorId);
        $plant = $this->getWithCacheMerge($userId, $plant);

        $seedId = $plant->getSeedId();
        if ($plant->getSeedId() == -1) {
            return array();
//            throw new SzException(20258, array($decorId, -1));
        }
        $status = $plant->getStatus();
        //未浇水不能收获
        if ($status == 0) {
            return array();
//            throw new SzException(20263, array($decorId));
        }

        $harvestTime = $plant->getHarvestTime();
        // 验证植株是否成熟
        if ($reqTime < $harvestTime) {
            return array();
//            throw new SzException(20255, array($seedId, $reqTime, $harvestTime));
        }

        /**
         * @var PlantSeedVo $seedVo
         */
        $seedList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_PLANT_SEED);
        $seedVo = $seedList->getElement($seedId);
        $cropSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_PLANT_CROP, $seedId, true);
        $cropParameterSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_PLANT_CROP_PARAMETER, $building->getBuildingDefId(), true);

        $count = $plant->getHarvestCount();
        if ($hasBuffFlower){
            $count = $count + 1;
        }
        //20200409
        //获取玩家该花朵是否具有种子掉落数量加成
        $seedBuff = FlowersUpgradeService::get()->getFlowerBuff($userId,$seedId,GameConst::FLOWER_TYPE_6);
        if (!empty($seedBuff)){
            if ($seedBuff[0] == 2){
                $count = $count + $seedBuff[1];
            }
            if ($seedBuff[0] == 1){
                $count = ceil($count*(1+$seedBuff[1]/100));
            }
        }
        $items = [$seedId => $count];

        // 收获种子
        $amount = $cropSetting['seedProp'][$plant->getLevel()];
        $weight = $cropSetting['seedWeight'][$plant->getLevel()];
        //20200409
        //获取玩家该花朵是否具有种子掉落概率加成
        $weightBuff = FlowersUpgradeService::get()->getFlowerBuff($userId,$seedId,GameConst::FLOWER_TYPE_4);
        if (!empty($weightBuff)){
            if ($weightBuff[0] == 2){
                $weight = $weight + $weightBuff[1];
            }
            if ($weightBuff[0] == 1){
                $weight = ceil($weight*(1+$weightBuff[1]/100));
            }
        }
        $rand = mt_rand(1,100);
        $isDrop = false;

        if ($hasBuffSeed){
            $amount = $amount + 1;
        }
        if (++$status > $cropSetting['frequency'][$plant->getLevel()]) {//收获次数已经到达上限
            $plant->setSeedId(-1);
            $plant->setStatus(0);
            $plant->setHarvestTime(0);
            $plant->setHarvestCount(0);
            $plant->setLevel(0);
            $plant->setStealInfo([]);
        } else {
            //20200409
            //获取玩家该花朵是否具有时间加成
            $getTime = $cropSetting['interval'][$plant->getLevel()];
            $flowerBuff = FlowersUpgradeService::get()->getFlowerBuff($userId,$seedId,GameConst::FLOWER_TYPE_5);
            if (!empty($flowerBuff)){
                if ($flowerBuff[0] == 2){
                    $getTime = $getTime - $flowerBuff[1];
                }
                if ($flowerBuff[0] == 1){
                    $getTime = ceil($getTime*(1-$flowerBuff[1]/100));
                }
            }

            $harvestCount = intval($cropSetting['cropCount'][$seedVo->getLevel()] * $cropParameterSetting['cropCount']);
            $plant->setStatus($status);
            $plant->setHarvestTime($reqTime + $getTime);
            $plant->setHarvestCount($harvestCount);
            $plant->setStealInfo([]);
        }
        // 更新植株
        $plantList->updateElement($decorId, $plant);
        SzPersister::get()->setVoList($plantList);
        // 收获道具
        list($itemList) = ItemService::get()->processItems($userId, $items);
        SzPersister::get()->setVoList($itemList);
        $outTid = $seedId . ':' . $count . '|';
        if ($rand <= $weight) {
            //20200409
            //获取玩家该花朵是否种子数量掉落加成
            $amountBuff = FlowersUpgradeService::get()->getFlowerBuff($userId,$seedId,GameConst::FLOWER_TYPE_3);
            if (!empty($amountBuff)){
                if ($amountBuff[0] == 2){
                    $amount = $amount + $amountBuff[1];
                }
                if ($amountBuff[0] == 1){
                    $amount = ceil($amount*(1+$amountBuff[1]/100));
                }
            }
            list($itemList) = ItemService::get()->processItems($userId, [$cropSetting['exp'] => $amount], $itemList);
            SzPersister::get()->setVoList($itemList);
            $outTid = $cropSetting['exp'] . ':' . $amount . '|';
            $isDrop = true;
        }
        if (isset($cropSetting['experience'])) {// 收获获得经验
            UserService::get()->updateExp($userId, $cropSetting['experience'][$seedVo->getLevel()]);
            //跟新店铺经营数据（经验）
            UserShopService::get()->record($userId,2,14000001,$cropSetting['experience'][$seedVo->getLevel()]);
            $outTid .= GameConst::ENTITY_ACTION_GET_EXP . ':' . $cropSetting['experience'][$seedVo->getLevel()] . '|';
        }
        //更新任务进度
        MissionService::get()->progress($userId, GameConst::ENTITY_ACTION_PLANT_HARVEST, GameConst::ENTITY_TYPE_ITEM, $seedId, 1);

        //清除偷花信息
        SzCacheFactory::get()->getAppCache($userId)->delete(GameConst::CACHE_KEY_PLANT_STEAL_INFO . $decorId . '_' . $userId);

        TrainingService::get()->updateProgress($userId,GameConst::TRAINING_TASK_HARVEST_FLOWER,1);
        $itemNum = 0;
        //验证活动是否开启
        $activityPersonalGoalsId = ActivityService::get()->getActivityPersonalGoalsIndexId($userId,$reqTime);
        if ($activityPersonalGoalsId) {
            $upper = 0;
            //获取植株配置
            $seedSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_PLANT_CROP, $seedId, true);
            $needTime = $seedSetting['interval'][0];
            //获取几率掉落结果
            $dropConfs = SzConfig::get()->loadAppConfig(GameConst::CONFIG_GAME_ACTIVITY_PLANT_PER_PLANT, null, true);
            if (!empty($needTime) && !empty($dropConfs)){
                //依据生长时间进行随机掉落道具数量
                foreach ($dropConfs as $key=>$data){
                    if ($needTime >= $data['rowthRange'][0] && $needTime <= $data['rowthRange'][1]){
                        $upper = $data['dropProbability'];
                        break;
                    }
                }
                if (!empty($upper)){
                    $mineNum = rand(0,100);
                    if ($mineNum <= $upper){
                        //发送给玩家活动道具
                        ActivityService::get()->updateActivityPersonalGoalsNum($userId,$activityPersonalGoalsId,1,false,true);
                        $itemNum = 1;
                    }
                }
            }
        }

        // 更新合约任务进度
        $contractData = ContractService::get()->getContractOpenAndTask($userId,GameConst::CONTRACT_TASK_5,$reqTime);
        if (!empty($contractData) && !empty($contractData['task']) && !empty($contractData['session'])){
            if ($reqTime >= $contractData['start'] && $reqTime <= $contractData['end']){
                ContractService::get()->updateTaskProgress($userId,$contractData['session'],$contractData['task']['pos'],$contractData['task']['taskId'],$reqTime);
            }
        }

        //社团竞赛任务进度添加
        UnionCompetitionService::get()->addCompetitionTaskProcess($userId,GameConst::UNION_COMPETITION_TASK_1, $reqTime,$count,$seedId);

        return array($seedId,$plant, $count,array($cropSetting['exp'] => $amount),$isDrop,$itemNum);
    }

    /**
     * 偷好友家花
     * @param int $userId
     * @param int $targetUserId
     * @param int $gridId
     * @param int $reqTime
     * @return array(status, count)
     * @throws SzException
     */
    public function stealFlower($userId, $targetUserId, $gridId, $reqTime)
    {
        if ($userId == $targetUserId) {
            return [7, 0];
        }
        /**
         * @var $targetFriendList NewFriendsVoList
         * @var $friendList NewFriendsVoList
         */
        $targetFriendList = SzPersister::get()->getVoList($targetUserId, GameConst::ORM_NAME_NEW_FRIEND);
        $targetFriendInfo = $targetFriendList->getElement($userId,false);
        if(!$targetFriendInfo) {
            return [8,0];
        }

        $friendList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_NEW_FRIEND);
        $friendInfo = $friendList->getElement($targetUserId,false);
        if(!$friendInfo) {
            return [8,0];
        }

        $totalCount = SzConfig::get()->loadAppConfig(ModuleProfileConst::CONFIG_PROFILE, 'umberOfMutualaid', true);
        //获取当天交互次数
        $friendCount = FriendService::get()->getFriendHandleInfo($userId, $targetUserId,$totalCount);
        if ($friendCount >= $totalCount['value']) {
            return [1, 0];
        }
        /**
         * @var BuildingVo $building
         */
        list($decorId) = BuildingService::get()->getGroundAndDecorRecord($targetUserId, $gridId, GameConst::GROUND_LAYER_TYPE_PLANT_LAYER_ID);

        $count = 0;
        /**
         * @var PlantVoList $plantList
         * @var PlantVo $plant
         */
        $plantList = SzPersister::get()->getVoList($targetUserId, GameConst::ORM_NAME_PLANT);
        $plant = $plantList->getElement($decorId);
        $plant = $this->getWithCacheMerge($targetUserId, $plant);

        $seedId = $plant->getSeedId();
        //验证是否有种植
        if ($seedId == -1) {
            return [2, $count];
        }
        //未浇水
        if ($plant->getStatus() == 0) {
            return [3, $count];
        }
        // 验证植株是否成熟
        if ($reqTime < $plant->getHarvestTime()) {
            return [4, $count];
        }

        $stealInfo = $plant->getRawStealInfo();
        //已经偷过
        if (isset($stealInfo[$userId])) {
            return [5, $count];
        }

        $cropSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_PLANT_CROP, $seedId, true);
        $harvestCount = $plant->getHarvestCount();

        //已经低于保底不能再偷了
        if ($harvestCount <= $cropSetting['baodi'][$plant->getLevel()]) {
            return [6, $count];
        }

        /**
         * @var PlantSeedVo $seedVo
         */
        $seedList = SzPersister::get()->getVoList($targetUserId, GameConst::ORM_NAME_PLANT_SEED);
        $seedVo = $seedList->getElement($seedId);

        $count = $cropSetting['stealing'][$plant->getLevel()];
        //偷完之后剩余数量不能低于保底数量
        if ($harvestCount - $count < $cropSetting['baodi'][$plant->getLevel()]) {
            $count = $harvestCount - $cropSetting['baodi'][$plant->getLevel()];
        }

        //增加偷菜缓存
        SzCacheFactory::get()->getAppCache($targetUserId)->hSet(GameConst::CACHE_KEY_PLANT_STEAL_INFO . $decorId . '_' . $targetUserId, $userId, $count);
        //偷花消息
        SocialService::get()->sendMessage($userId, $targetUserId, $plant->getSeedId(), $count, $reqTime);
        // 收获道具
        list($itemList) = ItemService::get()->processItems($userId, [$plant->getSeedId() => $count]);
        SzPersister::get()->setVoList($itemList);

        NewTaskService::get()->updateProgress($userId,GameConst::TASK_STEAL_FLOWER,$count);
        NewTaskService::get()->updateDailyTask($userId,GameConst::DAILY_TASK_STEAL_FLOWER,1);

        //修改当天交互次数
        FriendService::get()->updateFriendHandleInfo($targetUserId, $friendList, $friendInfo);

        // 更新任务进度---偷花
        MissionService::get()->progress($userId, GameConst::ENTITY_ACTION_FLOWER_STEALING, GameConst::ENTITY_TYPE_NULL, GameConst::ENTITY_PADDING_NULL, 1);

        // 数据采集:偷取花朵
        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_USER_ORBIT, array(
            'clientData' => array(
                'tid' => 'Module:friends|action:steal|',
                'item' => $targetUserId . '&' . $seedId,
                'value' => 1
            )
        ));

        // 数据采集:偷取好友产出
        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_RESOURCE_OUTPUT, array(
            'clientData' => array(
                'tid' => $plant->getSeedId() . ':' . $count . '|',
                'item' => 'friends_steal&' . $targetUserId
            )
        ));

        // 数据采集:偷取好友消耗交互次数
        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_RESOURCE_INPUT, array(
            'clientData' => array(
                'tid' => '7415999999999:1|',
                'item' => 'friends_steal&' . $targetUserId
            )
        ));
        return [0, $count];
    }

    /**
     * 加速成熟(使用加速道具/看视频)
     *
     * @param int $userId
     * @param int $gridId
     * @param int $reqTime
     * @param int $isFree
     * @throws SzException 20206
     * @return boolean
     */
    public function speedUp($userId, $gridId, $reqTime,$isFree = 0)
    {
        list($decorId) = BuildingService::get()->getGroundAndDecorRecord($userId, $gridId, GameConst::GROUND_LAYER_TYPE_PLANT_LAYER_ID);

        /**
         * @var PlantVoList $plantList
         * @var PlantVo $plant
         */
        $plantList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_PLANT);
        $plant = $plantList->getElement($decorId);
        $seedId = $plant->getSeedId();
        if ($seedId == -1) {
            throw new SzException(20258, array($decorId, $seedId));
        }
        if ($plant->getStatus() == 0) {
            throw new SzException(20263, array($decorId));
        }

        //使用道具加速
        if (!$isFree) {
            //消耗加速道具
            list($itemList) = ItemService::get()->processItems($userId, [GameConst::ITEM_ID_SPEED_UP_POTION => -1]);
            SzPersister::get()->setVoList($itemList);
        }

        // 直接成熟
        $plant->setHarvestTime($reqTime);
        $plantList->updateElement($decorId, $plant);
        SzPersister::get()->setVoList($plantList);

        // 数据采集: 农场植物速成
        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_USER_ORBIT, array(
            'clientData' => array(
                'tid' => 'Module:farm|action:speed|',
                'item' => $seedId,
                'value' => 1
            )
        ));


        // 数据采集: 加速消耗道具
        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_RESOURCE_INPUT, array(
            'clientData' => array(
                'tid' => GameConst::ITEM_ID_SPEED_UP_POTION . ':1|',
                'item' => 'farm_speed&' . $seedId
            )
        ));
        return true;
    }

    /**
     * 移除种植
     *
     * @param int $userId
     * @param int $gridId
     * @param int $reqTime
     * @throws SzException 20206
     * @return boolean
     */
    public function move($userId, $gridId, $reqTime)
    {
        list($decorId) = BuildingService::get()->getGroundAndDecorRecord($userId, $gridId, GameConst::GROUND_LAYER_TYPE_PLANT_LAYER_ID);

        /**
         * @var PlantVoList $plantList
         * @var PlantVo $plant
         */
        $plantList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_PLANT);
        $plant = $plantList->getElement($decorId);
        $seedId = $plant->getSeedId();
        if ($seedId == -1) {
            throw new SzException(20258, array($decorId, $seedId));
        }
        // 移除种植
        $plant->setSeedId(-1);
        $plant->setStatus(0);
        $plant->setHarvestTime(0);
        $plantList->updateElement($decorId, $plant);
        SzPersister::get()->setVoList($plantList);

        //清除偷花信息
        SzCacheFactory::get()->getAppCache($userId)->delete(GameConst::CACHE_KEY_PLANT_STEAL_INFO . $decorId . '_' . $userId);

        return true;
    }

    /**
     * 植株加速成熟
     *
     * @param int $userId
     * @param int $gridId
     * @param int $cliCost
     * @param int $reqTime
     * @throws SzException 20206
     * @return boolean
     */
    public function payForSpeedUp($userId, $gridId, $cliCost, $reqTime)
    {
        list($decorId) = BuildingService::get()->getGroundAndDecorRecord($userId, $gridId, GameConst::GROUND_LAYER_TYPE_PLANT_LAYER_ID);

        /**
         * @var PlantVoList $plantList
         * @var PlantVo $plant
         */
        $plantList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_PLANT);
        $plant = $plantList->getElement($decorId);
        $seedId = $plant->getSeedId();
        if ($seedId == -1) {
            throw new SzException(20258, array($decorId, $seedId));
        }

        $cropSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_PLANT_CROP, $plant->getSeedId(), true);
        GameService::get()->handleSpeedUp($userId, $cropSetting['coolDownId'], $plant->getHarvestTime(), $reqTime,
            (GameConst::ITEM_TYPE_SOIL_NORMAL == $cropSetting['type']) ? 'farm_speed_$seedId' : 'Pond_speed_$seedId', $cliCost);

        // 加速成熟
        $plant->setHarvestTime($reqTime);
        $plantList->updateElement($decorId, $plant);
        SzPersister::get()->setVoList($plantList);

        if (GameConst::ITEM_TYPE_SOIL_NORMAL == $cropSetting['type']) {
            // 数据采集：农场植物速成
            StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_USER_ORBIT, array(
                'clientData' => array(
                    'tid' => 'Module:farm|action:speed|',
                    'item' => $seedId,
                    'value' => 1
                )
            ));
        } else {
            // 数据采集：水域植物速成
            StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_USER_ORBIT, array(
                'clientData' => array(
                    'tid' => 'Module:Pond|action:speed|',
                    'item' => $seedId,
                    'value' => 1
                )
            ));
        }
        return true;
    }

    /**
     * 免费加速
     * @param $userId int
     * @param $gridId string
     * @param $reqTime int
     * @throws SzException
     * @return true
     */
    public function freeSpeedUp($userId, $gridId, $reqTime)
    {
        $gameSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_GAME, GameConst::DEFAULT_GAME_SETTING_KEY, true);
        list($decorId) = BuildingService::get()->getGroundAndDecorRecord($userId, $gridId, GameConst::GROUND_LAYER_TYPE_PLANT_LAYER_ID);

        /**
         * @var PlantVoList $plantList
         * @var PlantVo $plant
         */
        $plantList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_PLANT);
        $plant = $plantList->getElement($decorId);

        if (UserService::get()->getUserLevel($userId) > $gameSetting['newPlayerLv']) {
            throw new SzException(20259);
        }

        // 修改植株数据
        $plant->setHarvestTime($reqTime);
        $plantList->updateElement($decorId, $plant);
        SzPersister::get()->setVoList($plantList);

        return true;
    }

    /**
     * 种子升级
     * @param $userId
     * @param $seedId
     * @return array|PlantSeedVo|SzAbstractVo
     * @throws SzException
     */
    public function seedUpgrade($userId, $seedId)
    {
        $cropSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_PLANT_CROP, $seedId, true);
        /**
         * @var PlantSeedVo $seedVo
         */
        $seedList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_PLANT_SEED);
        $seedVo = $seedList->getElement($seedId);
        $level = $seedVo->getLevel();
        if (!isset($cropSetting['upgrade'][$level]) || !isset($cropSetting['coin'][$level])) {
            return $seedVo;
        }
        $count = $cropSetting['upgrade'][$level];
        $price = $cropSetting['coin'][$level];

        $tid = '';

        $videoList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_VIDEO);
        $video = $videoList->getElement($seedId, false);
        if (false && $cropSetting['freeVideoLevel'] == $level && !$video) {
            $video = new VideoVo($userId, $seedId, 1, GameService::get()->getReqTime());
            $videoList->addElement($video);
            $videoList->setElement($seedId, $video);
        } else {
            /**
             * @var ModuleItemVoList $itemList
             * @var ModuleItemVo $item
             */
            $itemList = SzPersister::get()->getVoList($userId, ModuleItemConst::ORM_NAME_ITEM);

            //扣除道具
            list($itemList) = ItemService::get()->processItems($userId, [$cropSetting['exp'] => -$count], $itemList);

            $seedEntityId = EntityService::get()->buildEntityId(GameConst::ENTITY_ACTION_GET, GameConst::ENTITY_TYPE_ITEM, $cropSetting['exp']);
            $tid = $seedEntityId.':'.$count.'|';


            // 扣除买家金币，增加买家物品放入仓库
            GameService::get()->handleEntity($userId, GameConst::ENTITY_ACTION_CONSUME_TOKEN, $price, true);
            $tid .= GameConst::ENTITY_ACTION_CONSUME_TOKEN.':'.$price.'|';

            SzPersister::get()->setVoList($itemList);
        }


        $level++;
        $seedVo->setLevel($level);
        $seedList->updateElement($seedId, $seedVo);

        SzPersister::get()->setVoList($seedList);
        SzPersister::get()->setVoList($videoList);
        // 数据采集: 鲜花升级
        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_USER_ORBIT, array(
            'clientData' => array(
                'tid' => 'Module:book|action:upgrade|',
                'item' => $seedId,
                'value' => 1
            )
        ));

        // 数据采集: 鲜花升级
        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_UPGRADE, array(
            'clientData' => array(
                'tid' => 'objective:book|item:' . $seedId . '|',
                'item' => 'fromlevel:' . ($level - 1) . '|changelev:1|targetlev:' . $level . '|',
                'value' => 1
            )
        ));

        // 消耗
        StatisticsService::get()->saveLog($userId, GameConst::LOG_TYPE_RESOURCE_INPUT, array(
            'clientData' => array(
                'tid' => $tid,
                'item' => 'book_upgrade&'.$seedId,
            )
        ));

        // 种子等级排行榜
        $isUp = SeedService::get()->setFlowerLevel($userId,GameService::get()->getReqTime(),true);

        //社团竞赛任务进度添加
        UnionCompetitionService::get()->addCompetitionTaskProcess($userId,GameConst::UNION_COMPETITION_TASK_3, GameService::get()->getReqTime(),1);

        return array(
            'plant' => $seedVo->toArray(),
            'isUp' => $isUp
        );
    }

    /**
     *  是否可以偷花
     * @param int $userId
     * @param int $targetUserId
     * @return bool
     */
    public function isCanStealFlower($userId, $targetUserId)
    {
        $reqTime = GameService::get()->getReqTime();
        /**
         * @var PlantVoList $plantList
         * @var PlantVo $plant
         */
        $plantList = SzPersister::get()->getVoList($targetUserId, GameConst::ORM_NAME_PLANT);
        $cropSettings = SzConfig::get()->loadAppConfig(GameConst::CONFIG_PLANT_CROP, null, true);
        foreach ($plantList->getList() as $decorId => $plant) {
            $plant = $this->getWithCacheMerge($targetUserId, $plant);
            $seedId = $plant->getSeedId();
            if ($seedId == -1 || $plant->getStatus() == 0 || $reqTime < $plant->getHarvestTime()) {
                continue;
            }
            $stealInfo = $plant->getRawStealInfo();
            if (isset($stealInfo[$userId])) {
                continue;
            }
            //已经低于保底不能再偷了
            if ($plant->getHarvestCount() <= $cropSettings[$seedId]['baodi'][$plant->getLevel()]) {
                continue;
            }
            return true;
        }
        return false;
    }

    //    /**
    //     * 种子升级
    //     * @param int $userId
    //     * @param int $seedId
    //     * @return PlantSeedVo
    //     */
    //    public function seedUpgrade($userId, $seedId)
    //    {
    //
    //        $cropSetting = SzConfig::get()->loadAppConfig(GameConst::CONFIG_PLANT_CROP, $seedId, true);
    //        /**
    //         * @var PlantSeedVo $seedVo
    //         */
    //        $seedList = SzPersister::get()->getVoList($userId, GameConst::ORM_NAME_PLANT_SEED);
    //        $seedVo = $seedList->getElement($seedId);
    //
    //        /**
    //         * @var ModuleItemVoList $itemList
    //         * @var ModuleItemVo $item
    //         */
    //        $itemList = SzPersister::get()->getVoList($userId, ModuleItemConst::ORM_NAME_ITEM);
    //        $count = $itemList->getItemDefCount($cropSetting['exp']);
    //        if (!$count) {
    //            return $seedVo;
    //        }
    //        //扣除道具
    //        list($itemList) = ItemService::get()->processItems($userId, [$cropSetting['exp'] => -$count], $itemList);
    //        SzPersister::get()->setVoList($itemList);
    //
    //        $exp = $seedVo->getExp() + $count;
    //        $level = $seedVo->getLevel();
    //        while (isset($cropSetting['upgrade'][$level]) && $exp > $cropSetting['upgrade'][$level]) {
    //            $level++;
    //            $exp -= $cropSetting['upgrade'][$level];
    //        }
    //        $seedVo->setExp($exp);
    //        $seedVo->setLevel($level);
    //        $seedList->updateElement($seedId, $seedVo);
    //        SzPersister::get()->setVoList($seedList);
    //        return $seedVo;
    //    }
}